package main;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;
import java.util.Random;
import java.util.Set;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class U {

	public static void Assert(boolean b) {
		if (!b) {
			throw new NullPointerException();
		}

	}

	public static BufferedReader newUtf8Reader(String in)
			throws UnsupportedEncodingException, FileNotFoundException {
		return new BufferedReader(new InputStreamReader(
				new FileInputStream(in), "UTF-8"));
	}

	public static BufferedWriter newUtf8writer(String string) throws Exception {
		return new BufferedWriter(new OutputStreamWriter(new FileOutputStream(
				string), "UTF-8"));
	}

	public static int getFileLineNum(String f) throws IOException {
		BufferedReader r = U.newReader(f);
		int res = 0;
		while (true) {
			String l = r.readLine();
			if (null == l)
				break;
			res++;
		}
		r.close();
		return res;
	}

	public static String TrimGood(String s) {
		if (null == s)
			return null;
		s = s.replace("\n", "");
		s = s.replace("\r", "");
		s = trimBeginAndEnd(s);
		return s;
	}

	public static boolean isEmpty(String s) {
		if (null == s || s.trim().equals(""))
			return true;
		return false;
	}

	public static void collection2file(AbstractCollection<String> c,
			String fpath) throws Exception {
		BufferedWriter w = newWriter(fpath);
		for (String s : c)
			w.write(s + '\n');
		w.close();
	}

	public static void closeW(Writer w) throws IOException {
		w.flush();
		w.close();
	}

	public static String getHTMLSrc(String url, String charSet)
			throws IOException {

		URL u = new URL(url);
		InputStream in = u.openStream();
		BufferedReader is = new BufferedReader(new InputStreamReader(in,
				charSet));
		String c = "";
		StringBuffer sb = new StringBuffer();
		while ((c = is.readLine()) != null) {
			sb.append(c).append("\n");// 读入数据
		}
		in.close();
		return U.TrimGood(new String(sb.toString()));
	}
	
	public static String getHTMLSource(String url)
	throws IOException {
		return U.getHTMLSrc(url, "utf-8");
}

	public static int getIndex(String[] sa, String s) {
		for (int i = 0; i < sa.length; i++) {
			if (sa[i].equals(s))
				return i;
		}
		return -1;
	}

	public static double minOr0(double[] da) {
		double res = 0;
		for (int i = 0; i < da.length; i++) {
			if (da[i] < res)
				res = da[i];
		}
		return res;
	}

	static List<String> getMatchedStringByRegex(String src, String regEx) {
		List<String> matchList = new ArrayList<String>();

		Pattern regex = Pattern.compile(regEx);
		Matcher regexMatcher = regex.matcher(src);
		while (regexMatcher.find()) {
			matchList.add(regexMatcher.group());
		}
		return matchList;
	}

	public static boolean isIn(int[] ia, int content) {
		for (int i = 0; i < ia.length; i++) {
			if (content == ia[i])
				return true;
		}
		return false;
	}

	public static boolean isIn(String[] ia, String content) {
		for (int i = 0; i < ia.length; i++) {
			if (content.equals(ia[i]))
				return true;
		}
		return false;
	}

	public static BufferedReader getReader(String file)
			throws FileNotFoundException {
		return new BufferedReader(new FileReader(file));
	}

	static boolean isDigit(String value) {
		try {
			Double.parseDouble(value);
			return true;
		} catch (NumberFormatException e) {
			return false;
		}
	}

	static boolean isInt(String value) {
		try {
			Integer.parseInt(value);
			return true;
		} catch (NumberFormatException e) {
			return false;
		}
	}

	static double truncation(double d) {
		int _d = (int) (d * 100);
		return ((double) _d) / 100;
	}

	public static BufferedWriter newWriter(String file) throws Exception {
		return U.newUtf8writer(file);
	}

	public static void add(HashMap<String, Integer> m, String s) {
		int i = 0;
		if (null != m.get(s))
			i = m.get(s);
		m.put(s, i + 1);
	}

	public static void add(Hashtable<String, Integer> m, String s) {
		int i = 0;
		if (null != m.get(s))
			i = m.get(s);
		m.put(s, i + 1);
	}

	public static double getExpectation(Vector<Double> v) {
		double result = 0;
		for (int i = 0; i < v.size(); i++) {
			result += v.get(i);
		}
		return result / v.size();
	}

	public static double getSD(Vector<Double> v) {
		double e = getExpectation(v);
		double result = 0;
		for (int i = 0; i < v.size(); i++) {
			result += (v.get(i) - e) * (v.get(i) - e);
		}
		return Math.sqrt(result / (v.size() - 1));
	}

	public static double relatedCoefficient(Vector<Double> v, Vector<Double> v2) {

		double res = 0;
		double e = getExpectation(v);
		double e2 = getExpectation(v2);
		for (int i = 0; i < v.size(); i++) {
			res += (v.get(i) - e) * (v2.get(i) - e2);
		}
		return res / getSD(v) / getSD(v2) / v.size();
	}

	public static int tryGet(HashMap<String, Integer> hm, String s) {
		if (null != hm.get(s))
			return hm.get(s);
		return 0;
	}

	public static int hashtableTryGet(Hashtable<String, Integer> hm, String s) {
		if (null != hm.get(s))
			return hm.get(s);
		return 0;
	}

	@SuppressWarnings("unchecked")
	public static Object getProperty(Object owner, String fieldName)
			throws Exception {
		Class ownerClass = owner.getClass();

		Field field = ownerClass.getField(fieldName);

		Object property = field.get(owner);

		return property;
	}

	public static double tryGetD(Hashtable<String, Double> ht, String key) {
		if (null != ht.get(key)) {
			return ht.get(key);
		}
		return 0;
	}

	public static float tryGetF(HashMap<String, Float> ht, String key) {
		if (null != ht.get(key)) {
			return ht.get(key);
		}
		return 0;
	}

	public static int tryGet(Hashtable<String, Integer> ht, String key) {
		if (null != ht.get(key)) {
			return ht.get(key);
		}
		return 0;
	}

	public static int tryGetI(Hashtable<String, Integer> ht, String key) {
		if (null != ht.get(key)) {
			return ht.get(key);
		}
		return 0;
	}

	public static BufferedReader newReader(String file) {
		try {
			return newUtf8Reader(file);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			System.err.println("fail to read file " + file);
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	public static String Array2String(Object[] a) {
		String res = "[";
		for (int i = 0; i < a.length; i++) {
			res += " " + a[i];
		}
		return res + " ]";
	}

	public static String Array2String(int[] a) {
		String res = "[";
		for (int i = 0; i < a.length; i++) {
			res += " " + a[i];
		}
		return res + " ]";
	}

	public static String Array2String(double[] a) {
		String res = "[";
		for (int i = 0; i < a.length; i++) {
			res += " " + a[i];
		}
		return res + " ]";
	}

	static int[] intSas2A(String s) {
		String[] sa = s.split(" ");
		int[] res = new int[sa.length - 2];
		for (int i = 1; i < sa.length - 1; i++) {
			res[i - 1] = Integer.parseInt(sa[i]);
		}
		return res;
	}

	static double[] doubleSas2A(String s) {
		String[] sa = s.split(" ");
		double[] res = new double[sa.length - 2];
		for (int i = 1; i < sa.length - 1; i++) {
			res[i - 1] = Double.parseDouble(sa[i]);
		}
		return res;
	}

	public static String trimBeginAndEnd(String s) {
		if (null == s || s.equals(""))
			return s;
		int i = 0;
		for (; i < s.length() && s.charAt(i) == ' '; i++)
			;
		if (i == s.length())
			return "";
		return s.substring(i).trim();
	}

	public static HashSet<String> loadHashSet(String f) throws IOException {
		BufferedReader r = U.newReader(f);
		HashSet<String> res = new HashSet<String>();
		while (true) {
			String l = r.readLine();
			if (null == l)
				break;
			res.add(l);
		}
		r.close();
		return res;
	}

	public static int[] arrayAdd(int[] a, int i) {
		int[] res = new int[a.length + 1];
		for (int j = 0; j < a.length; j++) {
			res[j] = a[j];
		}
		res[res.length - 1] = i;
		return res;
	}

	public static double[] arrayAdd(double[] a, double i) {
		double[] res = new double[a.length + 1];
		for (int j = 0; j < a.length; j++) {
			res[j] = a[j];
		}
		res[res.length - 1] = i;
		return res;
	}

	public static int getMaxIndex(int[] a) {
		int max = -Integer.MAX_VALUE;
		int index = -1;
		for (int i = 0; i < a.length; i++) {
			if (a[i] > max) {
				max = a[i];
				index = i;
			}

		}
		return index;
	}

	// ascending order
	public static int[] sort(int[] a) {
		if (a == null)
			return null;
		int[] res = new int[a.length];
		for (int i = res.length - 1; i >= 0; i--) {
			int j = U.getMaxIndex(a);
			res[i] = a[j];
			a[j] = -Integer.MAX_VALUE;
		}
		return res;
	}

	public static Vector<String> setMinus(Set<String> set1, Set<String> _set2) {
		Vector<String> res = new Vector<String>();
		for (String s1 : set1) {
			if (!_set2.contains(s1))
				res.add(s1);
		}
		return res;
	}

	@SuppressWarnings("unchecked")
	public static void setAdd(Set featureSet, Set featureSet2) {
		for (Object o : featureSet2)
			featureSet.add(o);

	}

	public static HashSet<String> vector2Set(Vector<String> v) {
		HashSet<String> set = new HashSet<String>();
		for (String f : v)
			set.add(f);
		return set;
	}

	public static HashSet<String> vector2HashSet(Vector<String> v) {
		HashSet<String> res = new HashSet<String>();
		for (String f : v)
			res.add(f);
		return res;
	}

	public static String[] set2Sa(Set<String> labels) {
		String[] res = new String[labels.size()];
		int i = 0;
		for (String o : labels) {
			res[i] = o;
			i++;
		}
		return res;
	}

	public static boolean StrIsEmpty(String s) {
		if (null == s || s.trim().equals(""))
			return true;
		return false;
	}

	public static String file2str(String file) {
		String res = "";
		BufferedReader br = U.newReader(file);
		try {
			while (true) {
				String l = br.readLine();
				if (null == l)
					break;
				res += l + "\n";
			}

			br.close();
		} catch (IOException e) {
			System.err.println("file to read file: " + file);
			e.printStackTrace();
		}
		if (res.length() > 0)
			res = res.substring(0, res.length() - 1);
		return res;
	}

	public static void str2file(String str, String file) throws Exception {
		FileWriter bw = new FileWriter(file,   true); 
		try {
			bw.write(str);
			bw.close();
		} catch (IOException e) {
			System.err.println("file to write file: " + file);
			e.printStackTrace();
		}
	}

	public static void appendStringToFile(String s, String fileName)
			throws IOException {
		BufferedWriter w = new BufferedWriter(new FileWriter(fileName, true));
		w.write(s);
		U.closeW(w);

	}

	public static void main(String[] args) throws Exception {
		
	}

	public synchronized static int getSelfIncressMutex(String countF, int mod)
			throws Exception {
		int count = Integer.parseInt(U.file2str(countF));
		count = (count + 1);
		if (mod > 0)
			count = count % mod;
		U.str2file(Integer.toString(count), countF);
		return count;
	}

	public static String processUrlString(String url) {
		if (null == url) {
			System.err.println("url is empty!");
			return null;
		}
		url = url.replace("%", "%25");
		url = url.replace(" ", "%20");
		url = url.replace("&", "%26");
		return url;
	}

	public static String preprocessStringForHttp(String s) {
		s = s.replace("%", " 25");
		s = s.replace(" ", "%20");
		s = s.replace("&", "%26");
		s = s.replace("=", "%3D");
		s = s.replace("#", "%23");
		return s;
	}

	public static String removeUnnecessaryBlank(String s) {
		return s.replaceAll(" +", " ");
	}

	public static void deleteFile(String srcTxt) {
		new File(srcTxt).delete();

	}

	// k integers from 1~(n-1)
	public static HashSet<Integer> getRandomK_Numbers(int n, int k) {
		Assert(n >= k);
		HashSet<Integer> res = new HashSet<Integer>();
		if (k == 0)
			return res;
		while (true) {
			int j = getRandomInt(n);
			if (!res.contains(j))
				res.add(j);
			if (res.size() == k)
				return res;

		}
	}

	// 0~(n-1)
	public static int getRandomInt(int n) {
		int i = new Random().nextInt(n);
		return i;
	}

	//(0,1) uniform distribution
	public static double getRandomNum() {
		return Math.random();
	}

	public static Vector<String> file2vector(String f) throws IOException {
		Vector<String> v = new Vector<String>();
		BufferedReader r = U.newReader(f);
		while (true) {
			String l = r.readLine();
			if (null == l)
				break;
			v.add(TrimGood(l));
		}
		r.close();
		return v;
	}

	// only bat in your java project dir, you can cd to other dir to excute
	// other bat
	public static void executeCommandLine(String order) throws IOException,
			InterruptedException {
		Process p = Runtime.getRuntime().exec(order);
		p.waitFor();
	}

	public static HashSet<String> file2hashSet(String file) throws Exception {
		HashSet<String> res = new HashSet<String>();
		Vector<String> v = U.file2vector(file);
		for (String ss : v)
			if (null != ss) {
				ss = U.TrimGood(ss);
				if (!ss.equals(""))
					res.add(ss);
			}
		return res;
	}

	public static void hashSet2file(HashSet<String> hs, String f)
			throws Exception {
		BufferedWriter w = U.newWriter(f);
		for (String s : hs)
			w.write(s + "\n");
		U.closeW(w);
	}

	public static Vector<String> hashSet2vector(HashSet<String> set) {
		Vector<String> res = new Vector<String>();
		for (String s : set)
			res.add(s);
		return res;
	}


	public static String toUtf8String(String s) {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < s.length(); i++) {
			char c = s.charAt(i);
			if (c >= 0 && c <= 255) {
				sb.append(c);
			} else {
				byte[] b;
				try {
					b = String.valueOf(c).getBytes("utf-8");
				} catch (Exception ex) {
					System.out.println(ex);
					b = new byte[0];
				}
				for (int j = 0; j < b.length; j++) {
					int k = b[j];
					if (k < 0)
						k += 256;
					sb.append("%" + Integer.toHexString(k).toUpperCase());
				}
			}
		}
		return sb.toString();
	}

	public static String unescape(String s) {
		StringBuffer sbuf = new StringBuffer();
		int l = s.length();
		int ch = -1;
		int b, sumb = 0;
		for (int i = 0, more = -1; i < l; i++) {
			/* Get next byte b from URL segment s */
			switch (ch = s.charAt(i)) {
			case '%':
				ch = s.charAt(++i);
				int hb = (Character.isDigit((char) ch) ? ch - '0'
						: 10 + Character.toLowerCase((char) ch) - 'a') & 0xF;
				ch = s.charAt(++i);
				int lb = (Character.isDigit((char) ch) ? ch - '0'
						: 10 + Character.toLowerCase((char) ch) - 'a') & 0xF;
				b = (hb << 4) | lb;
				break;
			case '+':
				b = ' ';
				break;
			default:
				b = ch;
			}
			/* Decode byte b as UTF-8, sumb collects incomplete chars */
			if ((b & 0xc0) == 0x80) { // 10xxxxxx (continuation byte)
				sumb = (sumb << 6) | (b & 0x3f); // Add 6 bits to sumb
				if (--more == 0)
					sbuf.append((char) sumb); // Add char to sbuf
			} else if ((b & 0x80) == 0x00) { // 0xxxxxxx (yields 7 bits)
				sbuf.append((char) b); // Store in sbuf
			} else if ((b & 0xe0) == 0xc0) { // 110xxxxx (yields 5 bits)
				sumb = b & 0x1f;
				more = 1; // Expect 1 more byte
			} else if ((b & 0xf0) == 0xe0) { // 1110xxxx (yields 4 bits)
				sumb = b & 0x0f;
				more = 2; // Expect 2 more bytes
			} else if ((b & 0xf8) == 0xf0) { // 11110xxx (yields 3 bits)
				sumb = b & 0x07;
				more = 3; // Expect 3 more bytes
			} else if ((b & 0xfc) == 0xf8) { // 111110xx (yields 2 bits)
				sumb = b & 0x03;
				more = 4; // Expect 4 more bytes
			} else /* if ((b & 0xfe) == 0xfc) */{ // 1111110x (yields 1 bit)
				sumb = b & 0x01;
				more = 5; // Expect 5 more bytes
			}
			/* We don't test if the UTF-8 encoding is well-formed */
		}
		return sbuf.toString();
	}



	public static Vector<String> getFileNameFromDir(String dir) {
		if (dir.charAt(dir.length() - 1) == '\\'
				|| dir.charAt(dir.length() - 1) == '/')
			dir = dir.substring(0, dir.length() - 1);
		File d = new File(dir);
		if (!d.exists())
			return null;
		Vector<String> res = new Vector<String>();
		File[] fs = d.listFiles();
		for (File f : fs)
			res.add(f.getName());
		return res;
	}

	public static String preprocessStrForHttptransmition(String q) {
		q = q.replaceAll("%", "%25");
		q = q.replaceAll("&", "%26");
		q = q.replaceAll("#", "%23");
		q = U.toUtf8String(q);
		q = q.replaceAll(" ", "%20");
		q = q.replaceAll("\t", "%09");
		return q;
	}

	public static String getPropertyValue(String filePath, String key) {
		Properties props = new Properties();
		try {
			InputStream in = new BufferedInputStream(new FileInputStream(
					filePath));
			props.load(in);
			String value = props.getProperty(key);
			return value;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	public static void vector2file(Vector res, String file) throws Exception {
		BufferedWriter w =U.newWriter(file);
		for(Object s:res)
			w.write(s.toString()+"\n");
		w.close();
	}

}
